package org.jeecg.common.util;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.crypto.digest.MD5;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import org.jeecg.common.api.vo.Result;

import java.util.Map;
import java.util.Random;
import java.util.TreeMap;

/**
 * api签名算法
 *
 * @author zhanglei01
 * @date 2022/03/04
 */
public class ApiSignUtil {
    /**
     * sign签名算法
     * 1. 将url参数对(除sign外)按key进行字典升序排序，得到有序的参数对列表N
     * 2. 将列表N中的参数对按URL键值对的格式拼接成字符串，得到字符串T
     * （如：appId=value1&nonceStr=value2&timestamp=value3）
     * 3. 将应用密钥以appSignKey为键名，组成URL键值拼接到字符串T末尾，得到字符串S
     * （如：appId=value1&nonceStr=value2&timestamp=value3&appSignKey=密钥)
     * 4. 对字符串S进行MD5运算，将得到的MD5值所有字符转换成大写，得到接口请求签名sign的值
     *
     * @param treeMap    待签名参数列表，有序({@link java.util.LinkedHashMap} 或 {@link TreeMap})，根据规则会忽略空值
     * @param appSignKey 应用的key
     * @return 签名字符串
     */
    public static String getReqSign(Map<String, Object> treeMap, String appSignKey) {
        StringBuffer uriSbd = new StringBuffer();
        for (Map.Entry<String, Object> entry : treeMap.entrySet()) {
            uriSbd.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
        }
        uriSbd.append("appSignKey=").append(appSignKey);
        //MD5加密后转大写
        return MD5.create().digestHex(uriSbd.toString()).toUpperCase();
    }


    /**
     * 获取时间戳
     *
     * @return {@link String}
     */
    public static String getTimestamp() {

        long timestampLong = System.currentTimeMillis();

        return String.valueOf(timestampLong);
    }

    /**
     * 获取随机数
     *
     * @param length 长度
     * @return {@link String}
     */
    public static String getNonceStr(int length) {

        //生成随机字符串
        String str = "zxcvbnmlkjhgfdsaqwertyuiopQWERTYUIOPASDFGHJKLZXCVBNM1234567890";
        Random random = new Random();
        StringBuffer randomStr = new StringBuffer();
        // 设置生成字符串的长度，用于循环
        for (int i = 0; i < length; ++i) {
            //从62个的数字或字母中选择
            int number = random.nextInt(62);
            //将产生的数字通过length次承载到randomStr中
            randomStr.append(str.charAt(number));
        }
        return randomStr.toString();
    }

    /**
     * gzip压缩
     *
     * @param toGzip gzip
     * @return {@link String}
     */
    public static String gzip(String toGzip) {
        return Base64.encode(ZipUtil.gzip(toGzip, CharsetUtil.CHARSET_UTF_8.name()));
    }

    /**
     * gzip解压
     *
     * @param toUnGzip gzip
     * @return {@link String}
     */
    public static String unGzip(String toUnGzip) {
        byte[] decode = Base64.decode(toUnGzip);
        return ZipUtil.unGzip(decode, CharsetUtil.CHARSET_UTF_8.name());
    }


    public static void main(String[] args) {
        //调用方appid
        String appId = "100001";
        //调用方appSignKey
        String appSignKey = "uj54d7gfb1ud3oaz";
        TreeMap<String, Object> treeMap = new TreeMap<>();
        treeMap.put("appId", appId);
        //随机数
        treeMap.put("nonceStr", getNonceStr(8));
        //时间戳
        treeMap.put("timestamp", getTimestamp());
        //生成签名
        String sign = getReqSign(treeMap, appSignKey);
        StringBuffer uriSbd = new StringBuffer();
        for (Map.Entry<String, Object> entry : treeMap.entrySet()) {
            uriSbd.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
        }
        String uriStr = uriSbd.append("sign=").append(sign).toString();
        String json = "{\"mobilePhone\": \"18617358020\"}";
        String url = "http://58.62.207.52:1455/tax-admin-thd/bg/api/cacheUserInfo?" + uriStr;
        System.out.println("请求地址: " + url);
        System.out.println("请求报文: " + json);
        String post = HttpUtil.post(url, json);
        System.out.println("返回报文(解密前): " + post);
        Result result = JSON.parseObject(post, Result.class);
        Object resultBody = result.getResult();
        //Base64转码后gzip解压
        String gzipStr = unGzip(resultBody.toString());
        System.out.println("===============================");
        System.out.println("返回业务报文(解密后): " + gzipStr);
    }

}
